home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 501-525 / disk_503 / pcq / pcq12asc.lzh / Runtime / PCQ / Openers.asm < prev    next >
Assembly Source File  |  1991-04-12  |  9KB  |  323 lines

  1.  
  2. *    Openers.asm (of PCQ Pascal runtime library)
  3. *    Copyright (c) 1989 Patrick Quaid
  4.  
  5. *    This file takes care of opening and closing DOS files.  In
  6. *    much the same way as the memory routines, these routines keep a
  7. *    list of the open files around.  Open() puts the files on the list
  8. *    and Close() takes them off.
  9.  
  10.     SECTION    PCQ_Runtime,CODE
  11.  
  12.     XREF    _p%DOSBase
  13.     XREF    _LVOOpen
  14.     XREF    _LVOIsInteractive
  15.     XREF    _LVOIoErr
  16.     XREF    _p%new
  17.     XREF    _p%dispose
  18.     XREF    _p%ExitWithAddr
  19.     XREF    _LVORead
  20.     XREF    _LVOClose
  21.     XREF    _p%IOResult
  22.     XREF    _p%FlushBuffer
  23.     XREF    i_lmul
  24.     XREF    i_ldiv
  25.  
  26.     XDEF    filekey
  27.  
  28. *    OpenB is the routine called by the open() and reopen() calls.
  29. *    It calls, in turn, Open, then returns true or false depending
  30. *    on whether there was an error.  It always clears IOResult.
  31.  
  32.  
  33. *    algorithm for open:
  34. *
  35. *    HANDLE := DOSOpen handle
  36. *    if then handle = nil
  37. *        set IOResult := IoErr
  38. *        return
  39. *    INTERACTIVE := IsInteractive
  40. *    if INTERACTIVE and (Access = ModeOldFile) then
  41. *        MAX := RECSIZE
  42. *    else
  43. *        MAX := (MAX div RECSIZE) * RECSIZE
  44. *        if MAX = 0 then
  45. *        MAX := RECSIZE
  46. *    Allocate BUFFER of size MAX
  47. *    if BUFFER = nil then
  48. *        close HANDLE
  49. *        set IOResult to 50
  50. *        return
  51. *    set MAX := BUFFER (First position) + MAX (buffer size)
  52. *    - thus MAX points to first byte AFTER buffer
  53. *    CURRENT := BUFFER
  54. *    LAST := BUFFER
  55. *    EOF := False
  56. *    if (Access = ModeOldFile) and (not INTERACTIVE) then
  57. *        FillBuffer
  58. *    link into file list
  59. *    return
  60.  
  61. * Upon entry, the stack looks like:
  62. *
  63. *    4(SP) -> Address of File Record
  64. *    8(SP) -> Address of File Name String
  65. *
  66. *    The File Record is initialized with the following values:
  67. *
  68. *    ACCESS    = either ModeOldFile or ModeNewFile
  69. *    RECSIZE    = the size of a record (1 for Text files)
  70. *    MAX    = the buffer size requested
  71. *
  72.  
  73.     INCLUDE    "/FileRec.i"
  74.  
  75.     XDEF    _p%Open
  76. _p%Open
  77.     move.l    4(sp),d0
  78.     move.l    8(sp),d1
  79.     move.l    d1,-(sp)
  80.     move.l    d0,-(sp)
  81.     bsr    _p%OpenB
  82.     tst.l    _p%IOResult
  83.     seq    d0
  84.     clr.l    _p%IOResult
  85.     add.w    #8,sp
  86.     rts
  87.  
  88.     XDEF    _p%OpenB
  89. _p%OpenB
  90.  
  91.  
  92.     move.l    8(sp),d1    ; get file name
  93.     move.l    4(sp),a0    ; get address of FileRec
  94.     moveq.l    #0,d2        ; clear out upper word
  95.     move.w    ACCESS(a0),d2    ; get access mode
  96.     move.l    _p%DOSBase,a6
  97.     jsr    _LVOOpen(a6)    ; open the file
  98.     move.l    4(sp),a0
  99.     move.l    d0,HANDLE(a0)    ; save the file handle
  100.     bne.s    OpenedOK    ; no errors
  101.     jsr    _LVOIoErr(a6)    ; get the error number
  102.     move.l    d0,_p%IOResult    ; set IOResult
  103.     rts            ; return
  104. OpenedOK
  105.     move.l    d0,d1        ; set up caller
  106.     jsr    _LVOIsInteractive(a6)    ; is it interactive ?
  107.     move.l    4(sp),a0    ; get file rec
  108.     move.b    d0,INTERACTIVE(a0)    ; set interactive
  109.     beq.s    AdjustBuffer    ; if not interactive, skip this
  110.     cmp.w    #1005,ACCESS(a0) ; is it an input file ?
  111.     bne.s    AdjustBuffer    ; if not, skip
  112.     move.l    RECSIZE(a0),d0    ; d0 := RECSIZE
  113.     move.l    d0,MAX(a0)    ; save size for later
  114.     bra.s    AllocBuffer    ; go to allocate the buffer
  115. AdjustBuffer
  116.     move.l    MAX(a0),d0    ; d0 := Buffer Size requested
  117.     move.l    RECSIZE(a0),d1    ; d1 := record size
  118.     jsr    i_ldiv        ; call 32-bit divide routines. d0/d1 in d0
  119.     tst.l    d0        ; is it zero?
  120.     bne.s    1$        ; if not, skip
  121.     moveq.l    #1,d0        ; at least 1
  122. 1$    move.l    4(sp),a0    ; get file rec
  123.     move.l    RECSIZE(a0),d1    ; d1 := record size again
  124.     jsr    i_lmul        ; d0 := (max div recsize) * recsize
  125.     move.l    4(sp),a0    ; get file rec address
  126.     move.l    d0,MAX(a0)    ; save it for later
  127. AllocBuffer
  128.     jsr    _p%new        ; allocate buffer
  129.     move.l    4(sp),a0    ; a0 := file record address
  130.     move.l    d0,BUFFER(a0)    ; set buffer
  131.     bne.s    InitializeFR    ; if OK, initialize record
  132.     move.l    HANDLE(a0),d1    ; set up for close
  133.     move.l    _p%DOSBase,a6    ; get DOS library base
  134.     jsr    _LVOClose(a6)    ; close the file
  135.     move.l    #50,_p%IOResult    ; Set IO Result = no memory for buffer
  136.     rts            ; return, having failed
  137. InitializeFR
  138.     move.l    MAX(a0),a1    ; get buffer size
  139.     adda.l    BUFFER(a0),a1    ; add to first address
  140.     move.l    a1,MAX(a0)    ; set maximum address: last byte + 1
  141.     move.l    BUFFER(a0),a1    ; a1 := first byte
  142.     move.l    a1,CURRENT(a0)    ; CURRENT := BUFFER
  143.     move.l    a1,LAST(a0)    ; LAST := BUFFER
  144.     move.b    #0,EOF(a0)    ; EOF := False
  145.     cmp.w    #1005,ACCESS(a0)    ; is input file ?
  146.     bne.s    LinkFile    ; if not, skip this
  147.     tst.b    INTERACTIVE(a0)    ; is it interactive ?
  148.     bne.s    LinkFile    ; if so, skip this
  149.     jsr    _p%FillBuffer    ; fill the buffer for input file
  150. LinkFile
  151.     move.l    filekey,NEXT(a0) ; a0.Next := filekey
  152.     move.l    a0,filekey    ; filekey := a0 (linked a0 into list)
  153.     rts            ; return successful
  154.  
  155.     XDEF    _p%FillBuffer
  156. _p%FillBuffer
  157.  
  158. * Read as many bytes as possible into the file's buffer
  159. * on entry, a0 is the address of the file record, which contains
  160. * all the important info.  This routine sets EOF
  161.  
  162. *    Algorithm:
  163. *
  164. *    if IOResult <> 0 then
  165. *        return
  166. *    if EOF then
  167. *        set IOResult and return
  168. *    Read MAX - BUFFER bytes into BUFFER
  169. *    CURRENT := BUFFER
  170. *    LAST := BUFFER + bytes read
  171. *    if LAST = BUFFER then
  172. *        EOF := True
  173. *
  174.  
  175.     tst.l    _p%IOResult    ; is IO OK?
  176.     bne    3$        ; if not, leave now
  177.     tst.b    EOF(a0)        ; at EOF?
  178.     beq.s    1$        ; if not, skip ahead
  179.     move.l    #51,_p%IOResult    ; set IOResult = Access past EOF
  180.     rts
  181. 1$    move.l    a0,-(sp)    ; save the File Rec
  182.     move.l    HANDLE(a0),d1    ; get the file handle
  183.     bne.s    2$        ; if it's open, skip
  184.     jsr    _p%MayOpenInput    ; if not, try to open input
  185.     move.l    HANDLE(a0),d1    ; if we got here, we must be OK
  186. 2$    move.l    BUFFER(a0),d2    ; get first address
  187.     move.l    d3,-(sp)    ; save d3
  188.     move.l    MAX(a0),d3    ; get last address + 1
  189.     sub.l    d2,d3        ; number of bytes to read
  190.     move.l    _p%DOSBase,a6    ; get dos.library
  191.     jsr    _LVORead(a6)
  192.     move.l    (sp)+,d3    ; restore d3
  193.     move.l    (sp)+,a0    ; get file record back
  194.     move.l    BUFFER(a0),d1    ; get initial position
  195.     move.l    d1,CURRENT(a0)    ; set CURRENT := initial
  196.     add.l    d0,d1        ; get BUFFER + bytes read
  197.     move.l    d1,LAST(a0)    ; LAST := BUFFER + bytes read
  198.     tst.l    d0        ; did we actually read anything?
  199.     bne.s    3$        ; if so, skip
  200.     move.b    #-1,EOF(a0)    ; set EOF := True
  201. 3$    rts
  202.  
  203. *    MayOpenInput
  204. *
  205. *    This routine opens a Standard Input window for programs that
  206. *    may have started from the Workbench.  It gets the window spec
  207. *    from _StdInName, which is defined either in the User program
  208. *    or, by default, in this library.  If the Output file is already
  209. *    open, and it's interactive, that already open file is used.
  210. *
  211. *    Algorithm for MayOpenInput:
  212. *
  213. *    if a0 <> Input then
  214. *        generate a runtime error
  215. *    if Output is open and interactive then
  216. *        Output.Handle := Input.Handle
  217. *    else
  218. *        Open(StdInName, Input)
  219. *        if it did not open OK
  220. *        generate a runtime error
  221. *
  222.  
  223. *    Upon entry to this routine, a0 holds the address of the
  224. *    File Record, which may or may not be Input.
  225.  
  226.     XREF    _p%exit
  227.     XREF    _StdInName
  228.     XREF    _Input
  229.     XREF    _Output
  230.  
  231. _p%MayOpenInput
  232.     cmpa.l    #_Input,a0    ; is it Input?
  233.     beq.s    1$        ; if so, skip this
  234.     move.l    #52,d0        ; runtime error
  235.     jsr    _p%ExitWithAddr    ; generate the error
  236. 1$    move.l    #_Output,a1    ; get Input ptr
  237.     tst.l    HANDLE(a1)    ; is it open?
  238.     beq    2$        ; if not, open a new one
  239.     tst.b    INTERACTIVE(a1)    ; is it interactive?
  240.     bne    2$        ; if not, open a new file
  241.     move.l    HANDLE(a1),a1    ; get the file handle
  242.     move.l    a1,HANDLE(a0)    ; and copy it over
  243.     rts            ; and try that one
  244. 2$    move.l    #80,MAX(a0)    ; set up for Open call
  245.     move.l    #1,RECSIZE(a0)    ; Text file
  246.     move.w    #1005,ACCESS(a0)    ; it's an input file (ModeOldFile)
  247.     move.l    _StdInName,-(sp)    ; push the file name
  248.     move.l    a0,-(sp)    ; push the file record address
  249.     jsr    _p%Open        ; try to open this file
  250.     move.l    (sp)+,a0    ; retrieve file record
  251.     addq.l    #4,sp        ; and fix stack
  252.     tst.b    d0        ; did it go OK?
  253.     bne.s    3$        ; if so, go on
  254.     move.l    #53,d0        ; if not, generate an error
  255.     jsr    _p%ExitWithAddr    ; goodbye
  256. 3$    rts            ; return to sender
  257.  
  258.  
  259. *    Close the file
  260. *
  261. *    This routine unlinks the file from the open-file list, then
  262. *    de-allocates the buffer and closes the file.  If the file
  263. *    is for some reason not on the open-file list, the routine
  264. *    attempts to close it and deallocate its buffer anyway.  Thus
  265. *    you can generate several types of errors by closing a file
  266. *    twice.
  267. *
  268. *    Algorithm:
  269. *
  270. *    if filekey <> nil then
  271. *        if filekey = FileRec then
  272. *        filekey := FileRec.NEXT
  273. *        else
  274. *        a1 := filekey
  275. *        while a1 <> nil do
  276. *            if a1.Next = FileRec then
  277. *            a1.Next := FileRec.Next
  278. *            skip ahead to FlushBuffer business
  279. *            a1 := a1.Next
  280. *    if ACCESS = ModeNewFile then
  281. *        FlushBuffer
  282. *    DOSClose(HANDLE)
  283. *    Dispose(BUFFER)
  284. *
  285. *    Upon entry, a0 holds the address of the file record
  286. *
  287.  
  288.     XDEF    _p%Close
  289. _p%Close:
  290.     move.l    filekey,a1        ; a1 := filekey
  291.     move.l    a1,d0            ; to set flags
  292.     beq    3$            ; if Nil, skip all this
  293.     cmpa.l    a1,a0            ; is a0 = filekey?
  294.     bne.s    1$            ; if not, go to loop
  295.     move.l    NEXT(a1),a1        ; unlink the first file
  296.     move.l    a1,filekey        ; set filekey := filekey.Next
  297.     bra    3$            ; go to flush buffer stuff
  298. 1$    cmpa.l    NEXT(a1),a0        ; a0 = NEXT(a1)
  299.     bne.s    2$            ; if not, skip this
  300.     move.l    a2,-(sp)        ; save a2 for now
  301.     move.l    NEXT(a0),a2        ; a2 := file after a0
  302.     move.l    a2,NEXT(a1)        ; a1.Next := a0.Next (lose a0)
  303.     move.l    (sp)+,a2        ; retrieve a2
  304.     bra.s    3$            ; and do the rest of close
  305. 2$    move.l    NEXT(a1),a1        ; advance file record ptr
  306.     move.l    a1,d0            ; are we at end of list?
  307.     bne.s    1$            ; if not, go on
  308. 3$    move.l    a0,-(sp)        ; save file record
  309.     cmp.w    #1006,ACCESS(a0)    ; was it ModeNewFile ?
  310.     bne.s    4$            ; if not, skip
  311.     jsr    _p%FlushBuffer        ; otherwise flush the buffer
  312. 4$    move.l    HANDLE(a0),d1        ; get handle
  313.     move.l    _p%DOSBase,a6        ; get DOS address
  314.     jsr    _LVOClose(a6)        ; close the file
  315.     move.l    (sp)+,a0        ; get file record back
  316.     move.l    BUFFER(a0),d0        ; get initial address
  317.     jsr    _p%dispose        ; de-allocate it
  318.     rts
  319.  
  320.     SECTION    FileKey
  321. filekey    dc.l    0
  322.     END
  323.